import org.xilin.User
import org.xilin.Role
import org.springframework.mail.javamail.MimeMailMessage
import javax.mail.internet.MimeMessage
import org.springframework.mail.javamail.MimeMessageHelper
import org.apache.commons.lang.RandomStringUtils;

/**
 * User controller.
 */
class UserController {

    def authenticateService
    def mailSender

    // the delete, save and update actions only accept POST requests
    static Map allowedMethods = [delete: 'POST', save: 'POST', update: 'POST']

    def index = {
        redirect action: list, params: params
    }

    def list = {
        if (!params.max) {
            params.max = 20
        }
        [personList: User.list(params)]
    }

    def show = {
        def person = User.get(params.id)
        if (!person) {
            flash.message = "User not found with id $params.id"
            redirect action: list
            return
        }
        List roleNames = []
        for (role in person.authorities) {
            roleNames << role.authority
        }
        roleNames.sort { n1, n2 ->
            n1 <=> n2
        }
        [person: person, roleNames: roleNames]
    }

    /**
     * Person delete action. Before removing an existing person,
     * he should be removed from those authorities which he is involved.
     */
    def delete = {

        def person = User.get(params.id)
        if (person) {
            def authPrincipal = authenticateService.principal()
            //avoid self-delete if the logged-in user is an admin
            if (!(authPrincipal instanceof String) && authPrincipal.username == person.username) {
                flash.message = "You can not delete yourself, please login as another admin and try again"
            }
            else {
                //first, delete this person from People_Authorities table.
                Role.findAll().each { it.removeFromPeople(person) }
                person.delete()
                flash.message = "User $params.id deleted."
            }
        }
        else {
            flash.message = "User not found with id $params.id"
        }

        redirect action: list
    }

    def edit = {

        def person = User.get(params.id)
        if (!person) {
            flash.message = "User not found with id $params.id"
            redirect action: list
            return
        }

        return buildPersonModel(person)
    }

    /**
     * Person update action.
     */
    def update = {

        def person = User.get(params.id)
        if (!person) {
            flash.message = "User not found with id $params.id"
            redirect action: edit, id: params.id
            return
        }

        long version = params.version.toLong()
        if (person.version > version) {
            person.errors.rejectValue 'version', "person.optimistic.locking.failure",
				"Another user has updated this User while you were editing."
            render view: 'edit', model: buildPersonModel(person)
            return
        }

        def oldPassword = person.passwd
        person.properties = params
        if (!params.passwd.equals(oldPassword)) {
            person.passwd = authenticateService.encodePassword(params.passwd)
        }
        if (person.save()) {
            Role.findAll().each { it.removeFromPeople(person) }
            addRoles(person)
            redirect action: show, id: person.id
        }
        else {
            render view: 'edit', model: buildPersonModel(person)
        }
    }

    def create = {
        [person: new User(params), authorityList: Role.list()]
    }

    /**
     * Person save action.
     */
    def save = {

        def person = new User()
        person.properties = params
        person.passwd = authenticateService.encodePassword(params.passwd)
        if (person.save()) {
            addRoles(person)
            redirect action: show, id: person.id
        }
        else {
            render view: 'create', model: [authorityList: Role.list(), person: person]
        }
    }

    private void addRoles(person) {
        for (String key in params.keySet()) {
            if (key.contains('ROLE') && 'on' == params.get(key)) {
                Role.findByAuthority(key).addToPeople(person)
            }
        }
    }

    private Map buildPersonModel(person) {

        List roles = Role.list()
        roles.sort { r1, r2 ->
            r1.authority <=> r2.authority
        }
        Set userRoleNames = []
        for (role in person.authorities) {
            userRoleNames << role.authority
        }
        LinkedHashMap<Role, Boolean> roleMap = [:]
        for (role in roles) {
            roleMap[(role)] = userRoleNames.contains(role.authority)
        }

        return [person: person, roleMap: roleMap]
    }

    def adminList = {
        def userInstanceList = User.list()
        render(template: "adminList", model: [userInstanceList: userInstanceList, userInstanceTotal: userInstanceList.count()])
    }

    def adminCreate = {
        def userInstance = null

        if (params.id) {
            userInstance = User.get(params.id)
        }
        else {
            userInstance = new User()
            userInstance.properties = params
        }
        def authority = userInstance?.authorities?.id ? Role.read(userInstance?.authorities?.id[0]).authority : 'ROLE_USER' 
        render(template: "adminCreate", model: [userInstance: userInstance, authority:authority])
    }

    def adminSave = {
        def userInstance = null

        if (params.id) {
            userInstance = User.get(params.id)
            userInstance.properties = params
        }
        else {
            userInstance = new User(params)
        }

        userInstance.passwd = authenticateService.passwordEncoder(params.passwd)
        def role = Role.findByAuthority(params.authority)
        role.addToPeople(userInstance)

        if (userInstance.save(flush:true)) {
            userInstance.refresh()
            redirect(action: "adminList")
        }
        else {
            userInstance.errors.allErrors.each {
                log.debug(it)
            }
            flash.message = "Missing required data for User"
            render(template: params.view, model: [userInstance: userInstance])
        }
    }

    def adminDelete = {
        def userInstance = User.get(params.id)
        if (userInstance) {
            try {
                userInstance.delete(flush: true)
                flash.message = "${message(code: 'default.deleted.message', args: [message(code: 'user.delete.label', default: 'User deleted'), params.username])}"
            }
            catch (org.springframework.dao.DataIntegrityViolationException e) {
                flash.message = "${message(code: 'default.not.deleted.message', args: [message(code: 'user.delete.label', default: 'Failed to delete user'), params.username])}"
            }
        }
        else {
            flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'user.label', default: 'User'), params.username])}"
        }

        redirect(action: "adminList")
    }

    def requestUserName = {
        render view: 'requestUserName'
    }

    def requestPassword = {
        render view: 'requestPassword'
    }

    def getUserName = {
        def user = User.findByEmail(params.email)
        String emailContent = "Your user name for Xilin Chinese School: ${user.username}"
        MimeMessage message = mailSender.createMimeMessage();
        MimeMessageHelper helper = new MimeMessageHelper(message);
        helper.setTo([user.email]);
        helper.setText(emailContent, true);
        helper.setSubject("[${request.contextPath}] Xilin Chinese School User Name")
        mailSender.send(message);
        render view: 'getUserName'
    }

    def getPassword = {
        def user = User.findByUsername(params.username)
        //   def password = authenticateService.passwordDecoder(user.passwd)
        String tempPassword = RandomStringUtils.random(8, true, false)
        user.passwd = authenticateService.encodePassword(tempPassword)
        if(user.save(flush:true)){
            String emailContent = "Your new password at Xilin Chinese School is: ${tempPassword}"
            MimeMessage message = mailSender.createMimeMessage();
            MimeMessageHelper helper = new MimeMessageHelper(message);
            helper.setTo([user.email]);
            helper.setText(emailContent, true);
            helper.setSubject("[${request.contextPath}] Xilin Chinese School Password")
            mailSender.send(message);
        }
        render view: 'getPassword'
    }

    def userRecover = {}

}
